﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Num = System.Int32;

namespace FAfx.SpectrumFish.Hardware
{
    public class Ports : FAfx.SpectrumFish.Interfaces.Hardware.IPorts
    {
        internal class KeyCode
        {
            internal Num row { get; set; }
            internal Num mask { get; set; }
        }

        internal Ports()
        {
            #region keyCodes
            keyCodes.Add(49, new KeyCode() { row = 3, mask = 0x01 }); /* 1 */
            keyCodes.Add(50, new KeyCode() { row = 3, mask = 0x02 }); /* 2 */
            keyCodes.Add(51, new KeyCode() { row = 3, mask = 0x04 }); /* 3 */
            keyCodes.Add(52, new KeyCode() { row = 3, mask = 0x08 }); /* 4 */
            keyCodes.Add(53, new KeyCode() { row = 3, mask = 0x10 }); /* 5 */
            keyCodes.Add(54, new KeyCode() { row = 4, mask = 0x10 }); /* 6 */
            keyCodes.Add(55, new KeyCode() { row = 4, mask = 0x08 }); /* 7 */
            keyCodes.Add(56, new KeyCode() { row = 4, mask = 0x04 }); /* 8 */
            keyCodes.Add(57, new KeyCode() { row = 4, mask = 0x02 }); /* 9 */
            keyCodes.Add(48, new KeyCode() { row = 4, mask = 0x01 }); /* 0 */

            keyCodes.Add(81, new KeyCode() { row = 2, mask = 0x01 }); /* Q */
            keyCodes.Add(87, new KeyCode() { row = 2, mask = 0x02 }); /* W */
            keyCodes.Add(69, new KeyCode() { row = 2, mask = 0x04 }); /* E */
            keyCodes.Add(82, new KeyCode() { row = 2, mask = 0x08 }); /* R */
            keyCodes.Add(84, new KeyCode() { row = 2, mask = 0x10 }); /* T */
            keyCodes.Add(89, new KeyCode() { row = 5, mask = 0x10 }); /* Y */
            keyCodes.Add(85, new KeyCode() { row = 5, mask = 0x08 }); /* U */
            keyCodes.Add(73, new KeyCode() { row = 5, mask = 0x04 }); /* I */
            keyCodes.Add(79, new KeyCode() { row = 5, mask = 0x02 }); /* O */
            keyCodes.Add(80, new KeyCode() { row = 5, mask = 0x01 }); /* P */

            keyCodes.Add(65, new KeyCode() { row = 1, mask = 0x01 }); /* A */
            keyCodes.Add(83, new KeyCode() { row = 1, mask = 0x02 }); /* S */
            keyCodes.Add(68, new KeyCode() { row = 1, mask = 0x04 }); /* D */
            keyCodes.Add(70, new KeyCode() { row = 1, mask = 0x08 }); /* F */
            keyCodes.Add(71, new KeyCode() { row = 1, mask = 0x10 }); /* G */
            keyCodes.Add(72, new KeyCode() { row = 6, mask = 0x10 }); /* H */
            keyCodes.Add(74, new KeyCode() { row = 6, mask = 0x08 }); /* J */
            keyCodes.Add(75, new KeyCode() { row = 6, mask = 0x04 }); /* K */
            keyCodes.Add(76, new KeyCode() { row = 6, mask = 0x02 }); /* L */
            keyCodes.Add(13, new KeyCode() { row = 6, mask = 0x01 }); /* enter */

            keyCodes.Add(16, new KeyCode() { row = 0, mask = 0x01 }); /* caps */
            keyCodes.Add(192, new KeyCode() { row = 0, mask = 0x01 }); /* backtick as caps - because firefox screws up a load of key codes when pressing shift */
            keyCodes.Add(90, new KeyCode() { row = 0, mask = 0x02 }); /* Z */
            keyCodes.Add(88, new KeyCode() { row = 0, mask = 0x04 }); /* X */
            keyCodes.Add(67, new KeyCode() { row = 0, mask = 0x08 }); /* C */
            keyCodes.Add(86, new KeyCode() { row = 0, mask = 0x10 }); /* V */
            keyCodes.Add(66, new KeyCode() { row = 7, mask = 0x10 }); /* B */
            keyCodes.Add(78, new KeyCode() { row = 7, mask = 0x08 }); /* N */
            keyCodes.Add(77, new KeyCode() { row = 7, mask = 0x04 }); /* M */
            keyCodes.Add(17, new KeyCode() { row = 7, mask = 0x02 }); /* sym - gah, firefox screws up ctrl+key too */
            keyCodes.Add(32, new KeyCode() { row = 7, mask = 0x01 }); /* space */
            #endregion
        }


        public override bool Equals(Object obj)
        {
            bool ret = false;

            // Check for null values and compare run-time types.
            if (obj == null || GetType() != obj.GetType())
                return ret;

            Ports t = (Ports)obj;
            var hasMismatches = (borderColor == t.borderColor) && Enumerable.Range(0, 8).ToList().Exists(x => keyStates[x] != t.keyStates[x]);
            return !hasMismatches;

        }
        //-----------------------------------------------------------------------;

        internal Num borderColor = 7;

        internal Dictionary<Num, KeyCode> keyCodes = new Dictionary<Num, KeyCode>();
        internal Num[] keyStates = new Num[8] { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };

        public void keyDown(Num evt_keyCode)
        {
            var keyCode = keyCodes[evt_keyCode];
            if (keyCode == null) return;
            this.keyStates[keyCode.row] &= ~(keyCode.mask);
        }

        public void keyUp(Num evt_keyCode)
        {
            var keyCode = keyCodes[evt_keyCode];
            if (keyCode == null) return;
            this.keyStates[keyCode.row] |= keyCode.mask;
        }

        public Num readport(Num addr)
        {
            if ((addr & 0x0001) == 0x0000)
            { //* read keyboard *@/
                var result = 0xff;
                for (var row = 0; row < 8; row++)
                {
                    if (!((addr & (1 << (row + 8))) > 0))
                    { //* bit held low, so scan this row *@/
                        result &= this.keyStates[row];
                    }
                }
                return result;
            }
            else if ((addr & 0x00e0) == 0x0000)
            {
                //* kempston joystick: treat this as attached but unused *@/
                //* (for the benefit of Manic Miner) *@/
                return 0x00;
            }
            else
            {
                return 0xff; //* unassigned port *@/
            }
        }

        public void writeport(Num addr, Num val)
        {
            if ((addr & 0x0001) == 0)
            {
                this.borderColor = val;
            }
        }

    }
}
